import React from 'react'
import ReactDOM from 'react-dom';
import classnames from 'classnames';
import {InputItem, Tools, Button, List} from 'weaver-mobile';
import uniqueId from 'lodash/uniqueId';
import * as Api from '../../apis/widget/mailInput';
const getLabel = Tools.getLabel;

const emailValidate = v =>
  !/[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/.test(v);
class Email {
  key = '';
  email = '';
  name = '';
  id = '';//适应formParams的需要
  error = false;
  constructor(email, name) {
    this.email = email;
    this.id = email;
    this.key = uniqueId('email_');
    this.error = emailValidate(email);
    this.name = name || '';
  }
}
/*
const getElemPos = (obj) => {
  var pos = {"top":0, "left":0};
  if (obj.offsetParent){
    while (obj.offsetParent){
      pos.top += obj.offsetTop;
      pos.left += obj.offsetLeft;
      obj = obj.offsetParent;
    }
  }
  pos.top += obj.offsetTop;
  pos.left += obj.offsetLeft;
  return {top:pos.left, left:pos.top};
}
*/

export const convertToEmail = (value) => {
  if (!value) return [];
  // 去重
  const filterMap = {};
  const filter = (item, index) => {
    if (filterMap[item.email]) return false;
    filterMap[item.email] = true;
    return true;
  }
  if (typeof(value) === 'string')
    return value.split(',').map((email) => new Email(email)).filter(filter);
  if (Array.isArray(value)) {
    return value.map((item) => {
      if (item instanceof Email) {
        return item;
      } else {
        return new Email(item.id, item.name);
      }
    }).filter(filter);
  }
  return [];
}
/**
 * 邮件地址输入框
 */
export default class MailInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: [],
      inputValue: '',
      selectedKey: '',
      showAll: false,//是否展示所有地址
      searchList: [],
      listTop: 0,
    };
  }
  componentDidMount() {
    this.setState({value: convertToEmail(this.props.value)});
    document.addEventListener('click', this.checkActive)
  }
  componentWillReceiveProps(nextProps) {
    if (nextProps.value !== this.props.value) {
      this.setState({value: convertToEmail(nextProps.value)})
    }
  }
  componentWillUnmount() {
    document.removeEventListener('click', this.checkActive);
    if (this.listRenderTarget) {
      this.listRenderTarget.remove();
    }
  }
  componentDidUpdate(prevProps, prevState) {
    if (this._container) {
      // console.log("offsetTop", this._container.offsetTop, "offsetHeight", this._container.offsetHeight);
      // let listTop = this._container.offsetTop + this._container.offsetHeight;
      // const pos = getElemPos(this._container);
      // console.log("pos", pos);
      // let listTop = pos.top + this._container.offsetHeight;
      const bodyPos = this._container.getBoundingClientRect();
      // console.log("bodyPos", bodyPos);
      let listTop = bodyPos.top + this._container.offsetHeight;
      if (listTop !== this.state.listTop) {
        this.setState({listTop});
      }
    }
  }
  render() {
    const {value, inputValue, selectedKey, showAll, searchList, listTop} = this.state,
      prefixCls = 'mail-input', hiddenCls = `${prefixCls}-hidden`;
    return (
      <div
        className={classnames(prefixCls, this.props.className)}
        onClick={this.showAll}
        ref={(x) => this._container = x}
      >
        {Array.isArray(value) && value.length > 0 &&
        (showAll ? value.map((item) => (
            <div
              key={item.key}
              className={classnames(
                `${prefixCls}-tag`,
                selectedKey === item.key ? `${prefixCls}-tag-selected` : '',
                item.error ? `${prefixCls}-tag-error` : '',
              )}
              onClick={() => this.setSelectedKey(item.key)}
            >
              <span>{/*为了背景色好上色与换行效果，加了这个span*/}
                {item.name || item.email}
              </span>
            </div>
          )) :
          <div>
            <div className={classnames(
              `${prefixCls}-tag`,
              value[0].error ? `${prefixCls}-tag-error` : '',
              value.length > 1 ? `${prefixCls}-tag-small` : '',
            )}>
              <span>{/*为了背景色好上色与换行效果，加了这个span*/}
                {value[0].name || value[0].email}
              </span>
            </div>
            {value.length > 1 && (getLabel(126387, '等') + value.length + getLabel(500497, '人'))}
          </div>
        )}
        <div className={classnames(`${prefixCls}-input-div`, showAll ? '' : hiddenCls)}>
          {/*用于监听删除事件，触发其它动作时会清除selectedKey*/}
          <InputItem
            className={classnames(selectedKey ? '' : hiddenCls)}
            onKeyDown={this.onHideKeyDown}
            onKeyUp={() => {}}
            onKeyPress={() => {}}
            value={inputValue}
            onChange={this.onChange}
            onClick={this.clearSelectedKey}
            ref={(el) => this.hideInputEl = el}
          />
          {/*用于直接输入*/}
          <InputItem
            className={classnames(!selectedKey ? '' : hiddenCls)}
            onKeyDown={this.onKeyDown}
            onKeyUp={this.onKeyUp}
            onKeyPress={this.onKeyPress}
            value={inputValue}
            onChange={this.onChange}
            onFocus={this.clearSelectedKey}
            ref={(el) => this.inputEl = el}
          />
          {/*用于监听安卓上的下一步逻辑,界面上用width:0隐藏了起来*/}
          <InputItem
            className={classnames(`${prefixCls}-next-input`,!selectedKey ? '' : hiddenCls)}
            onFocus={(e) => this.onSave(e)}
          />
          <Button
            className={inputValue ? '' : hiddenCls}
            disabled={!inputValue}
            type="primary"
            onClick={this.onSave}
          >
            {getLabel(826, '确定')}
          </Button>
        </div>
        {showAll && inputValue && searchList && searchList.length !== 0 &&
          ReactDOM.createPortal(
            (
              <div
                className={classnames(`${prefixCls}-search-list`, 'wm-route-layout')}
                style={{
                  top: listTop,
                }}
              >
                <List>
                  {searchList.map((item, index) => (
                    <List.Item
                      className={classnames(`${prefixCls}-search-list-item`)}
                      key={`${item.id}-${index}`}
                      multipleLine
                      onClick={(e) => this.add(e, item.id, item.name)}
                    >
                      <div className={classnames(`${prefixCls}-search-list-item-name`)}>{item.name}</div>
                      <div className={classnames(`${prefixCls}-search-list-item-email`)}>{item.id}</div>
                    </List.Item>
                  ))}
                </List>
              </div>
            ),
            this.getListRenderTarget(),
          )
        }
      </div>
    );
  }
  
  onKeyDown = (e) => {
    this.onPress(e);
  }
  
  onKeyUp = (e) => {
    // this.onPress(e);
  }
  onKeyPress = (e) => {
    // this.onPress(e);
  }
  
  /**
   * 邮箱输入框按压事件处理
   * @param e
   */
  onPress = (e) => {
    if (e.which === 8 || e.which === 13 || e.which === 46) {
      switch(e.which) {
        case 8: this.onDel(e);break;
        case 46: this.onDel(e);break;
        case 13: this.onEnter(e);break;
        default: break;
      }
    }
  }
  
  /**
   * 触发删除事件
   * 如果输入框中已被清空，则选中上方的最后一条邮箱
   * @param e
   */
  onDel = (e) => {
    const {value, inputValue} = this.state;
    if (!inputValue && Array.isArray(value) && value.length > 0) {
      this.setSelectedKey(value[value.length - 1].key);
    }
  }
  
  /**
   * 触发回车事件
   * @param e
   */
  onEnter = (e) => {
    this.onSave(e);
    e.preventDefault();
  }
  
  /**
   * 保存输入框中的内容
   * @param e
   */
  onSave = (e) => {
    let inputValue = this.state.inputValue;
    if (!inputValue) return;
    let splitChar = ';,';                     //定义分隔符
    let matchRegExp = new RegExp(`[^${splitChar}].*?(?=([${splitChar}](?=[^>]*(?:<|$))))|[^${splitChar}].*?.?$`, 'g');                 //分隔符分割输入的数据
    let changeRegExp = new RegExp('<(.+?)>', 'g');          //查找是否存在<>
    let replaceRegExp = new RegExp('[<>\\s]+', 'g');        //去除<>及空格
    let mailReg = /[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/g;
    let emailMatch = inputValue ? inputValue.trim().match(matchRegExp) : [];   //判断最后一项是否存在数据
    let lastValue = [];
    emailMatch && emailMatch.length > 0 && emailMatch.map(item => {
      item = item.trim();
      let change = item.match(changeRegExp);                                          //查找是否存在<>
      let username = '';
      if (change) {
        item = item.replace(/[^>]*$/, '');                                            //清除最后一个<>后的内容
        username = item.match(/^.*</)[0].replace(/<$/, '').trim();             //查找最后一个<前的内容
        change = change[change.length - 1].replace(replaceRegExp, '');
        if(lastValue.indexOf(change)==-1){
          lastValue.push(change);
        }
      } else {
        let searchSpace = item.search(/\s/);                                              //检测是否存在空格
        if (searchSpace >= 0) {
          change = item.match(/[^\s]*$/)[0];                                                  //查找最后一个空格后的内容为邮件地址
          if(lastValue.indexOf(change)==-1){
            lastValue.push(change);
          }
        }
      }
    })
    
    this.add(e, lastValue.length>0?lastValue.join(","):inputValue, inputValue)
  }
  
  /**
   * 在隐藏的输入框中按键，此时的操作点在上方的邮箱。
   * 按下的键如果是删除键，则删除对应的邮箱，并阻止删除输入框内容。
   * 如果不是删除键，则操作点转为输入框，邮箱选中效果消失
   * @param e
   */
  onHideKeyDown = (e) => {
    if (e.which === 8 || e.which === 46) {
      this.del(e);
      e.preventDefault();
    } else {
      this.clearSelectedKey();
    }
  }
  
  /**
   * 删除一个已经添加的邮箱
   * @param e
   */
  del = (e) => {
    if (this.state.selectedKey) {
      this.setState({
        value: this.state.value.filter((item) => item.key !== this.state.selectedKey),
      }, () => {
        this.props.onChange && this.props.onChange(e, this.state.value);
      });
      this.clearSelectedKey();
    }
  }
  
  /**
   * 清除上方所选的要删除的邮箱，并将焦点回到输入框中
   */
  clearSelectedKey = () => {
    this.setState({selectedKey: ''}, () => {
      this.inputEl.focus({preventScroll:true});//组件现在没有往下传，这个不能生效
    });
  }
  
  /**
   * 设置所选择邮箱，并将焦点置入隐藏输入框中
   * @param key
   */
  setSelectedKey = (key) => {
    this.setState({selectedKey: key}, () => {
      this.hideInputEl.focus({preventScroll:true});//组件现在没有往下传，这个不能生效
    });
  }
  
  checkActive = (e) => {
    if (!this.state.showAll) return;
    const thisDom = ReactDOM.findDOMNode(this);
    if (thisDom && !thisDom.contains(e.target)) {
      let inputDom = this.inputEl && this.inputEl.inputRef && this.inputEl.inputRef.inputRef,
        hideInputDom = this.hideInputEl && this.hideInputEl.inputRef && this.hideInputEl.inputRef.inputRef;
      if (inputDom !== document.activeElement
        && hideInputDom  !== document.activeElement) {
        this.setState({showAll: false, selectedKey: ''});
      }
    }
  }
  showAll = () => {
    this.setState({showAll: true},() => this.inputEl.focus());
  }
  
  /**
   * 输入时进行搜索
   * @param v
   */
  onChange = (v) => {
    this.setState({inputValue: v});
    const {handleOverflow} = this.props;
    if (v) {
      Api.searchMailList({q:v}).then((result) => {
        if (this.state.inputValue === v) {
          handleOverflow && handleOverflow(false);
          this.setState({
            searchList: result.datas
          });
        }
      });
    } else {
      handleOverflow && handleOverflow(true);
      this.setState({
        searchList: []
      });
    }
  }
  /**
   * 添加一条记录
   */
  add = (e, email, name) => {
    let {value} = this.state;
    if (!Array.isArray(value)) value = [];
    value = value.filter((item) => item.email !== email);//如果有重复的，去掉
    const {handleOverflow} = this.props;
    this.setState({
      value: [
        ...value,
        new Email(email, name),
      ],
      inputValue: '',
      searchList: [],
    }, () => {
      this.props.onChange && this.props.onChange(e, this.state.value);
      handleOverflow && handleOverflow(true);
      this.inputEl.focus();
    });
  }
  
  /**
   * 获得List渲染位置
   * @returns {HTMLDivElement | *}
   */
  getListRenderTarget() {
    if (!this.listRenderTarget) {
      this.listRenderTarget = document.createElement("div");
      document.body.appendChild(this.listRenderTarget);
    }
    return this.listRenderTarget;
  }
}
